"""
错误处理装饰器和中间件
自动记录错误日志到系统日志
"""
import functools
import traceback
import json
from flask import request, current_app
from flask_login import current_user
from services.shared.log_utils import log_error, log_system_event

def log_exceptions(module_name):
    """
    装饰器：自动记录函数异常到系统日志
    
    Args:
        module_name: 模块名称，用于日志分类
    """
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except Exception as e:
                # 获取详细的异常信息
                error_details = {
                    'function': func.__name__,
                    'args': str(args) if args else None,
                    'kwargs': str(kwargs) if kwargs else None,
                    'traceback': traceback.format_exc(),
                    'request_url': request.url if request else None,
                    'request_method': request.method if request else None,
                }
                
                # 记录错误日志
                user_id = None
                if hasattr(current_user, 'id') and current_user.is_authenticated:
                    user_id = current_user.id
                
                log_error(
                    module=module_name,
                    message=f"函数 {func.__name__} 发生异常: {str(e)}",
                    details=json.dumps(error_details, ensure_ascii=False),
                    user_id=user_id
                )
                
                # 重新抛出异常，保持原有的异常处理逻辑
                raise
        return wrapper
    return decorator

def log_api_exceptions(func):
    """
    API专用异常记录装饰器
    自动识别模块名称并记录API异常
    """
    # 从函数的模块路径推断模块名称
    module_name = 'api'
    if hasattr(func, '__module__'):
        module_parts = func.__module__.split('.')
        if 'web' in module_parts:
            module_name = 'web_api'
        elif 'scheduler' in module_parts:
            module_name = 'scheduler_api'
        elif 'executor' in module_parts:
            module_name = 'executor_api'
    
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            # 获取详细的API异常信息
            error_details = {
                'api_endpoint': func.__name__,
                'request_url': request.url if request else None,
                'request_method': request.method if request else None,
                'request_args': dict(request.args) if request else None,
                'request_json': request.get_json(silent=True) if request else None,
                'request_form': dict(request.form) if request and request.form else None,
                'user_agent': request.headers.get('User-Agent') if request else None,
                'remote_addr': request.remote_addr if request else None,
                'error_type': type(e).__name__,
                'error_message': str(e),
                'stack_trace': traceback.format_exc(),
                'function_args': str(args) if args else None,
                'function_kwargs': str(kwargs) if kwargs else None,
                'execution_context': {
                    'function': func.__name__,
                    'module': module_name
                }
            }
            
            # 获取当前用户信息
            user_id = None
            username = None
            if hasattr(current_user, 'id') and current_user.is_authenticated:
                user_id = current_user.id
                username = getattr(current_user, 'username', 'unknown')
            
            # 记录详细的API错误日志
            log_error(
                module="api_error_handler",
                message=f"API {func.__name__} 调用失败: {str(e)}",
                details={
                    "api_endpoint": func.__name__,
                    "user_id": user_id,
                    "username": username,
                    "request_details": error_details,
                    "error_type": type(e).__name__,
                    "error_message": str(e),
                    "stack_trace": traceback.format_exc(),
                    "execution_context": {
                        "function": func.__name__,
                        "module": module_name,
                        "operation": "api_request_handling"
                    }
                },
                user_id=user_id
            )
            
            # 重新抛出异常，保持原有的异常处理逻辑
            raise
    return wrapper

def register_error_handlers(app):
    """
    注册Flask应用的全局错误处理器
    自动记录所有未捕获的异常
    """
    @app.errorhandler(Exception)
    def handle_exception(e):
        """处理所有未捕获的异常"""
        # 获取异常详情
        error_details = {
            'type': e.__class__.__name__,
            'message': str(e),
            'traceback': traceback.format_exc(),
            'request_url': request.url if request else None,
            'request_method': request.method if request else None,
            'request_data': request.get_json(silent=True) if request else None,
            'user_agent': request.headers.get('User-Agent') if request else None,
        }
        
        # 记录系统错误日志
        user_id = None
        if hasattr(current_user, 'id') and current_user.is_authenticated:
            user_id = current_user.id
        
        log_system_event(
            level='ERROR',
            module='system',
            message=f"未捕获的异常: {e.__class__.__name__}: {str(e)}",
            details=json.dumps(error_details, ensure_ascii=False)
        )
        
        # 根据请求类型返回不同的响应
        if request and request.path.startswith('/api/'):
            from flask import jsonify
            from services.shared.utils import create_response
            return jsonify(create_response(False, '服务器内部错误')), 500
        else:
            from flask import render_template
            return render_template('errors/500.html'), 500
    
    @app.errorhandler(404)
    def handle_not_found(e):
        """处理404错误"""
        # 记录404错误（可选，通常404不需要记录）
        if current_app.config.get('LOG_404_ERRORS', False):
            log_system_event(
                level='WARNING',
                module='web',
                message=f"404错误: {request.url if request else 'Unknown'}",
                details=json.dumps({
                    'request_url': request.url if request else None,
                    'request_method': request.method if request else None,
                    'user_agent': request.headers.get('User-Agent') if request else None,
                }, ensure_ascii=False)
            )
        
        if request and request.path.startswith('/api/'):
            from flask import jsonify
            from services.shared.utils import create_response
            return jsonify(create_response(False, '接口不存在')), 404
        else:
            from flask import render_template
            return render_template('errors/404.html'), 404
    
    @app.errorhandler(403)
    def handle_forbidden(e):
        """处理403权限错误"""
        # 记录权限错误（安全相关）
        user_id = None
        if hasattr(current_user, 'id') and current_user.is_authenticated:
            user_id = current_user.id
        
        log_system_event(
            level='WARNING',
            module='security',
            message=f"权限被拒绝: {request.url if request else 'Unknown'}",
            details=json.dumps({
                'request_url': request.url if request else None,
                'request_method': request.method if request else None,
                'user_id': user_id,
                'user_agent': request.headers.get('User-Agent') if request else None,
            }, ensure_ascii=False)
        )
        
        if request and request.path.startswith('/api/'):
            from flask import jsonify
            from services.shared.utils import create_response
            return jsonify(create_response(False, '权限不足')), 403
        else:
            from flask import render_template
            return render_template('errors/403.html'), 403

class ErrorLoggingMiddleware:
    """
    WSGI中间件：记录所有HTTP错误
    """
    def __init__(self, app):
        self.app = app
    
    def __call__(self, environ, start_response):
        def new_start_response(status, response_headers, exc_info=None):
            # 检查HTTP状态码
            status_code = int(status.split(' ', 1)[0])
            
            # 记录HTTP错误状态码
            if status_code >= 400:
                log_system_event(
                    level='ERROR' if status_code >= 500 else 'WARNING',
                    module='http',
                    message=f"HTTP错误: {status}",
                    details=json.dumps({
                        'status_code': status_code,
                        'path': environ.get('PATH_INFO'),
                        'method': environ.get('REQUEST_METHOD'),
                        'remote_addr': environ.get('REMOTE_ADDR'),
                        'user_agent': environ.get('HTTP_USER_AGENT'),
                    }, ensure_ascii=False)
                )
            
            return start_response(status, response_headers, exc_info)
        
        return self.app(environ, new_start_response)